"""
配置管理模块

处理配置文件加载、环境变量、命令行参数等配置来源的统一管理。
"""

import os
import yaml
import json
from pathlib import Path
from typing import Dict, Any, Optional, Union
from .schemas import ConfigSchema


class Settings:
    """配置管理器
    
    支持多层配置覆盖：
    默认配置 < 配置文件 < 环境变量 < 命令行参数
    """
    
    def __init__(self, config_file: Optional[Union[str, Path]] = None):
        """初始化配置管理器
        
        Args:
            config_file: 配置文件路径，如果为None则使用默认配置
        """
        self._config: Optional[ConfigSchema] = None
        self._config_file = config_file
        self._load_config()
    
    def _load_config(self) -> None:
        """加载配置"""
        # 1. 从默认配置开始
        config_data = self._get_default_config()
        
        # 2. 加载配置文件
        if self._config_file:
            file_config = self._load_config_file(self._config_file)
            config_data = self._merge_config(config_data, file_config)
        else:
            # 尝试加载默认配置文件
            default_files = [
                "config/default.yaml",
                "es-archive.yaml",
                "es-archive.yml",
                ".es-archive.yaml"
            ]
            for file_path in default_files:
                if os.path.exists(file_path):
                    file_config = self._load_config_file(file_path)
                    config_data = self._merge_config(config_data, file_config)
                    break
        
        # 3. 加载环境变量
        env_config = self._load_env_config()
        config_data = self._merge_config(config_data, env_config)
        
        # 4. 验证并创建配置对象
        self._config = ConfigSchema(**config_data)
    
    def _get_default_config(self) -> Dict[str, Any]:
        """获取默认配置"""
        return {
            "elasticsearch": {
                "hosts": ["localhost:9200"],
                "timeout": 30,
                "request_timeout": 60,
                "max_retries": 3,
                "ssl_verify": True
            },
            "time_handling": {
                "default_time_field": "@timestamp",
                "auto_detect_time_field": True,
                "time_field_candidates": [
                    "@timestamp", "timestamp", "created_at", 
                    "updated_at", "event_time", "log_time"
                ],
                "timezone": {
                    "source": "auto",
                    "target": "UTC",
                    "handle_dst": True
                },
                "formats": {
                    "auto_detect": True,
                    "supported_formats": [
                        "strict_date_optional_time",
                        "epoch_millis",
                        "epoch_second",
                        "yyyy-MM-dd HH:mm:ss",
                        "yyyy/MM/dd HH:mm:ss"
                    ]
                },
                "range": {
                    "default_precision": "second",
                    "include_boundaries": True,
                    "max_range_days": 365
                }
            },
            "backup": {
                "chunk_size": "100MB",
                "compression": "gzip",
                "parallel_workers": 4,
                "include_mappings": True,
                "time_based": {
                    "enable_incremental": True,
                    "overlap_buffer": "1h",
                    "sort_by_time": True
                }
            },
            "restore": {
                "batch_size": 500,  # 降低默认批量大小以避免内存问题
                "parallel_workers": 2,
                "validate_data": True,
                "create_index": True,
                "adaptive_batch_size": True,  # 启用自适应批量大小
                "circuit_breaker_retry": True,  # 启用断路器重试
                "max_memory_usage": "500MB",  # 最大内存使用量
                "max_retries": 3,  # 最大重试次数
                "time_based": {
                    "preserve_timestamps": True,
                    "adjust_timezone": False,
                    "validate_time_range": True
                }
            },
            "storage": {
                "backend": "local",
                "local": {
                    "base_path": "./backups",
                    "create_subdirs": True
                },
                "compression": {
                    "algorithm": "gzip",
                    "level": 6
                }
            },
            "logging": {
                "level": "INFO",
                "file": "es-archive.log",
                "max_size": "10MB",
                "backup_count": 5,
                "time_format": "ISO8601",
                "include_timezone": True
            },
            "monitoring": {
                "enable_progress": True,
                "enable_metrics": True,
                "metrics_interval": 10
            },
            "security": {
                "mask_sensitive_data": True,
                "audit_log": True
            }
        }
    
    def _load_config_file(self, file_path: Union[str, Path]) -> Dict[str, Any]:
        """加载配置文件
        
        Args:
            file_path: 配置文件路径
            
        Returns:
            配置字典
            
        Raises:
            FileNotFoundError: 配置文件不存在
            ValueError: 配置文件格式错误
        """
        file_path = Path(file_path)
        
        if not file_path.exists():
            raise FileNotFoundError(f"配置文件不存在: {file_path}")
        
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                if file_path.suffix.lower() in ['.yaml', '.yml']:
                    return yaml.safe_load(f) or {}
                elif file_path.suffix.lower() == '.json':
                    return json.load(f) or {}
                else:
                    raise ValueError(f"不支持的配置文件格式: {file_path.suffix}")
        except Exception as e:
            raise ValueError(f"配置文件解析错误 {file_path}: {e}")
    
    def _load_env_config(self) -> Dict[str, Any]:
        """从环境变量加载配置
        
        环境变量格式: ES_ARCHIVE_<SECTION>_<KEY>
        例如: ES_ARCHIVE_ELASTICSEARCH_HOSTS
        """
        config = {}
        prefix = "ES_ARCHIVE_"
        
        for key, value in os.environ.items():
            if not key.startswith(prefix):
                continue
            
            # 移除前缀并转换为小写
            config_key = key[len(prefix):].lower()
            
            # 解析嵌套键
            parts = config_key.split('_')
            current = config
            
            for part in parts[:-1]:
                if part not in current:
                    current[part] = {}
                current = current[part]
            
            # 尝试转换值类型
            current[parts[-1]] = self._convert_env_value(value)
        
        return config
    
    def _convert_env_value(self, value: str) -> Union[str, int, float, bool, list]:
        """转换环境变量值类型"""
        # 布尔值
        if value.lower() in ('true', 'false'):
            return value.lower() == 'true'
        
        # 数字
        try:
            if '.' in value:
                return float(value)
            else:
                return int(value)
        except ValueError:
            pass
        
        # 列表 (逗号分隔)
        if ',' in value:
            return [item.strip() for item in value.split(',')]
        
        # 字符串
        return value
    
    def _merge_config(self, base: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any]:
        """合并配置字典
        
        Args:
            base: 基础配置
            override: 覆盖配置
            
        Returns:
            合并后的配置
        """
        result = base.copy()
        
        for key, value in override.items():
            if key in result and isinstance(result[key], dict) and isinstance(value, dict):
                result[key] = self._merge_config(result[key], value)
            else:
                result[key] = value
        
        return result
    
    def update_from_cli_args(self, **kwargs) -> None:
        """从命令行参数更新配置
        
        Args:
            **kwargs: 命令行参数字典
        """
        if not kwargs:
            return
        
        # 将当前配置转换为字典
        current_config = self._config.dict()
        
        # 构建CLI配置覆盖
        cli_config = self._build_cli_config(kwargs)
        
        # 合并配置
        merged_config = self._merge_config(current_config, cli_config)
        
        # 重新验证并创建配置对象
        self._config = ConfigSchema(**merged_config)
    
    def _build_cli_config(self, cli_args: Dict[str, Any]) -> Dict[str, Any]:
        """构建CLI配置字典"""
        config = {}
        
        # ES连接相关
        if 'es_host' in cli_args:
            config.setdefault('elasticsearch', {})['hosts'] = cli_args['es_host']
        if 'es_username' in cli_args:
            config.setdefault('elasticsearch', {})['username'] = cli_args['es_username']
        if 'es_password' in cli_args:
            config.setdefault('elasticsearch', {})['password'] = cli_args['es_password']
        
        # 时间处理相关
        if 'time_field' in cli_args:
            config.setdefault('time_handling', {})['default_time_field'] = cli_args['time_field']
        
        # 备份相关
        if 'chunk_size' in cli_args:
            config.setdefault('backup', {})['chunk_size'] = cli_args['chunk_size']
        if 'compression' in cli_args:
            config.setdefault('backup', {})['compression'] = cli_args['compression']
        if 'parallel_workers' in cli_args:
            config.setdefault('backup', {})['parallel_workers'] = cli_args['parallel_workers']
        
        # 恢复相关
        if 'batch_size' in cli_args:
            config.setdefault('restore', {})['batch_size'] = cli_args['batch_size']
        
        # 存储相关
        if 'output_dir' in cli_args:
            config.setdefault('storage', {}).setdefault('local', {})['base_path'] = cli_args['output_dir']
        
        # 日志相关
        if 'log_level' in cli_args:
            config.setdefault('logging', {})['level'] = cli_args['log_level']
        
        return config
    
    @property
    def config(self) -> ConfigSchema:
        """获取配置对象"""
        return self._config
    
    def get(self, key: str, default: Any = None) -> Any:
        """获取配置值
        
        Args:
            key: 配置键，支持点号分隔的嵌套键
            default: 默认值
            
        Returns:
            配置值
        """
        keys = key.split('.')
        current = self._config.dict()
        
        for k in keys:
            if isinstance(current, dict) and k in current:
                current = current[k]
            else:
                return default
        
        return current
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return self._config.dict()
    
    def to_yaml(self) -> str:
        """转换为YAML字符串"""
        return yaml.dump(self.to_dict(), default_flow_style=False, allow_unicode=True)
    
    def save_to_file(self, file_path: Union[str, Path]) -> None:
        """保存配置到文件
        
        Args:
            file_path: 文件路径
        """
        file_path = Path(file_path)
        
        with open(file_path, 'w', encoding='utf-8') as f:
            if file_path.suffix.lower() in ['.yaml', '.yml']:
                yaml.dump(self.to_dict(), f, default_flow_style=False, allow_unicode=True)
            elif file_path.suffix.lower() == '.json':
                json.dump(self.to_dict(), f, indent=2, ensure_ascii=False)
            else:
                raise ValueError(f"不支持的文件格式: {file_path.suffix}")


# 全局配置实例
_settings: Optional[Settings] = None


def get_settings(config_file: Optional[Union[str, Path]] = None) -> Settings:
    """获取全局配置实例
    
    Args:
        config_file: 配置文件路径
        
    Returns:
        配置实例
    """
    global _settings
    if _settings is None:
        _settings = Settings(config_file)
    return _settings


def reload_settings(config_file: Optional[Union[str, Path]] = None) -> Settings:
    """重新加载配置
    
    Args:
        config_file: 配置文件路径
        
    Returns:
        新的配置实例
    """
    global _settings
    _settings = Settings(config_file)
    return _settings
